<template>
    <div class="stats" ref="statsRef"></div>
    <div class="container" ref="containerRef"></div>
</template>

<script setup>

import { ref, reactive, onMounted, onActivated, watch } from 'vue'
import {
    Scene, PerspectiveCamera, WebGLRenderer, Color, AxesHelper, PlaneGeometry, Mesh,
    BoxGeometry, SphereGeometry, SpotLight, MeshLambertMaterial,
    OrthographicCamera
} from 'three'
import * as dat from 'dat.gui'

// 性能监控star==================================>性能监控
import Stats from 'stats.js'
const stats = new Stats()
stats.showPanel(0)
stats.dom.style.top = '50px'
const statsRef = ref(null)
// 切换相机添加
const cameraRef = ref(null)
// 性能监控end==================================>性能监控

const containerRef = ref(null)
// 交互控制star==================================>交互控制
const controlRef = ref({
    rotationSpeed: 0.02, bouncingSpeed: 0.03,
    numberOfObjdets: 0,  //基础场景添加
    addCube: function () {
        const cubeGeometry = new BoxGeometry(4, 4, 4)
        const cube = new Mesh(cubeGeometry, cubeMaterial)
        cube.name = "cube-" + scene.children.length
        cube.castShadow = true
        cube.position.x = -30 + Math.round((Math.random() * 60))
        cube.position.y = Math.round((Math.random() * 5))
        cube.position.z = -20 + Math.round((Math.random() * 40))
        scene.add(cube)
        this.numberOfObjdets = scene.children.length
        console.log(this.numberOfObjdets)
    },  //基础场景添加
    remove: function () {
        const allChidren = scene.children
        const lastObject = allChidren[allChidren.length - 1]
        console.log('lastObject', lastObject, allChidren)
        if (lastObject instanceof Mesh && lastObject.name.startsWith('cube')) {
            scene.remove(lastObject)
        }
        this.numberOfObjdets = scene.children.length
        console.log(this.numberOfObjdets)
    },  //基础场景添加
    // 相机切换增加
    camera:'Perspective',
    switchCamera:function() {
        console.log(222)
        if (this.camera == 'Perspective') {
            console.log(11)
            this.camera = 'Orthographic'
        } else {
            console.log(22)
            this.camera = 'Perspective'
        }
    }
})
// 交互控制end==================================>交互控制

// 创建一个场景
const scene = new Scene()


// // 创建一个摄像机，所谓摄像机就是模拟人眼从哪个视角（位置开始观察）
// // 参数一为角度，参数二为框高比，参数三位观察的最近的距离，参数四为观察最远距离
// const camera = new PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000)

// // 设置相机摆放的位置分别代表x，y，z的坐标
// camera.position.set(-30, 40, 30)

// // 设置相机的朝向
// camera.lookAt(scene.position)

// 初始化渲染,设置渲染的容器
const renderer = new WebGLRenderer()
// 设置渲染的颜色，这个颜色也可以放rgb的颜色
renderer.setClearColor(new Color(0xeeeeee))
renderer.setSize(window.innerWidth, window.innerHeight)

// 设置渲染器容器支持阴影star==================================>材质和关照的使用
renderer.shadowMap.enabled = true
// 设置渲染器容器支持阴影end==================================>材质和关照的使用

// 创建一个灯光star==================================>材质和关照的使用
// 设置颜色
const spotLight = new SpotLight(0xffffff)
// 设置是否阴影
spotLight.castShadow = true
// 设置灯光位置
spotLight.position.set(-40, 60, -10)
// 设置灯光强度
spotLight.intensity = 10000;
scene.add(spotLight)
// 创建一个灯光end==================================>材质和关照的使用


// 为场景增加一个右手坐标系,参数代表坐标系大小
const axes = new AxesHelper(20)
scene.add(axes)



// 添加一个平面材质 参数为材质大小
const planeGeometry = new PlaneGeometry(60, 40)
// 设置材质颜色
const meshBasicMaterial = new MeshLambertMaterial({ color: 0xcccccc }) // 修改材质为MeshLambertMaterial=======>材质和关照的使用
const plane = new Mesh(planeGeometry, meshBasicMaterial)
// 设置材质支持阴影star==================================>材质和关照的使用
plane.receiveShadow = true
// 设置材质支持阴影end==================================>材质和关照的使用
// 设置材质位置
plane.rotation.x = -0.5 * Math.PI
// plane.position.x = 15
// plane.position.y = 0
// plane.position.z = 0
// 增加材质
scene.add(plane)

// 继续增加一个立体矩形材质(这是一个立体的几何体)，三个参数分别代表长宽高，现在三个值相同那么就表示是一个正方体
const cubeGeometry = new BoxGeometry(4, 4, 4)
// wireframe表示填充否，True不填充，false填充
const cubeMaterial = new MeshLambertMaterial({
    color: 0xff0000,
    wireframe: false  // 修改wireframe为false===========>材质和关照的使用
}) // 修改材质为MeshLambertMaterial=======>材质和关照的使用
const cube = new Mesh(cubeGeometry, cubeMaterial)
// 设置材质支持阴影star==================================>材质和关照的使用
cube.castShadow = true
// 设置材质支持阴影end==================================>材质和关照的使用
cube.position.set(2, 2, 2)
scene.add(cube)

for (let j = 0; j < planeGeometry.parameters.height / 2; j++) {
    for (let i = 0; i < planeGeometry.parameters.width / 2; i++) {
        const cube = new Mesh(cubeGeometry, cubeMaterial)
        cube.position.z = -(planeGeometry.parameters.height / 2) + 2 + j * 5
        cube.position.x = -(planeGeometry.parameters.width / 2) + 2 + i * 5
        cube.position.y = 0
        scene.add(cube)
    }
}

// 继续增加一个球体材质
const sphereGeometry = new SphereGeometry(4)
const sphereMaterial = new MeshLambertMaterial({
    color: 0x7777ff,
    wireframe: false  // 修改wireframe为false===========>材质和关照的使用
})
const sphere = new Mesh(sphereGeometry, sphereMaterial)
// 设置材质支持阴影star==================================>材质和关照的使用
sphere.castShadow = true
// 设置材质支持阴影end==================================>材质和关照的使用
sphere.position.x = 20
sphere.position.y = 4
sphere.position.z = 2
scene.add(sphere)

// 增加动画star==================================>材质和关照增加动画
let step = 0
function renderScene() {
    // 性能监控end==================================>性能监控
    stats.update()
    // 性能监控end==================================>性能监控

    scene.traverse((e) => {
        // console.log(e.name)
        if (e.name.startsWith('cube')) {
            e.rotation.x += controlRef.value.rotationSpeed
            e.rotation.y += controlRef.value.rotationSpeed
            e.rotation.x += controlRef.value.rotationSpeed
        }
    })

    cube.rotation.x += controlRef.value.rotationSpeed
    cube.rotation.y += controlRef.value.rotationSpeed
    cube.rotation.x += controlRef.value.rotationSpeed
    step += controlRef.value.bouncingSpeed
    sphere.position.x = 20 + 10 * Math.cos(step)
    sphere.position.y = 2 + 10 * Math.abs(Math.sin(step))
    // 对页面渲染的每一帧的时候增加动画渲染
    requestAnimationFrame(renderScene)
    if (cameraRef.value) {
        renderer.render(scene, cameraRef.value)
    }

}

renderScene()
// 增加动画end==================================>材质和关照增加动画


// 交互控制end==================================>交互控制
function initGUI() {
    if (document.querySelectorAll(".dg.ac>.dg.main.a").length == 0) {
        const gui = new dat.GUI
        gui.add(controlRef.value, 'rotationSpeed', 0, 0.5)
        gui.add(controlRef.value, 'bouncingSpeed', 0, 0.5)
        gui.add(controlRef.value, 'numberOfObjdets').listen()  //基础场景添加
        gui.add(controlRef.value, 'addCube') //基础场景添加
        gui.add(controlRef.value, 'remove') //基础场景添加
        gui.add(controlRef.value, 'camera').listen() //相机切换增加
        gui.add(controlRef.value, 'switchCamera') //相机切换增加
    }
}

initGUI()
// 交互控制end==================================>交互控制

onMounted(() => {
    // 切换相机添加
    cameraRef.value = new PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000)
    // 设置相机摆放的位置分别代表x，y，z的坐标
    cameraRef.value.position.set(-120, 60, 180)

    // 设置相机的朝向
    cameraRef.value.lookAt(scene.position)
    // 性能监控star==================================>性能监控
    statsRef.value?.appendChild(stats.dom)
    // 性能监控end==================================>性能监控
    // 将渲染出来的容器放入到页面中 
    containerRef.value?.appendChild(renderer.domElement)
    // 增加场景,参数一为场景，参数二维相机（其实就是想前面创建的场景跟相机增加进来渲染）
    if (cameraRef.value) {
        renderer.render(scene, cameraRef.value)
    }
})

watch(()=>controlRef.value.camera,(n)=>{
    console.log("as",n)
    if(n=='Orthographic') {
        cameraRef.value = new OrthographicCamera(window.innerWidth/-16,window.innerHeight/16,window.innerHeight/16,window.innerHeight/-16,-200,500    )
        // 设置相机摆放的位置分别代表x，y，z的坐标
    cameraRef.value.position.set(-120, 60, 180)

    // 设置相机的朝向
    cameraRef.value.lookAt(scene.position)
    } else {
        cameraRef.value = new PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000)
    // 设置相机摆放的位置分别代表x，y，z的坐标
    cameraRef.value.position.set(-120, 60, 180)

    // 设置相机的朝向
    cameraRef.value.lookAt(scene.position)
    }
})
// 响应式窗口star==================================>响应式窗口
window.addEventListener('resize', () => {
    if (cameraRef.value) {
        console.log('变化', window.innerHeight, window.innerWidth, window.innerHeight / window.innerWidth)
        cameraRef.value.aspect = window.innerHeight / window.innerWidth
        // 更新相机投影矩阵
        cameraRef.value.updateProjectionMatrix()
    }

    renderer.setSize(window.innerWidth, window.innerHeight)
}, false)
// 响应式窗口end==================================>响应式窗口
onActivated(() => {

})


</script>

<style lang='less' scoped>
.container {
    height: 100vh;
    width: 100vh;
}
</style>